﻿using System;
using SqlSugar;
using SqlSugar.IOC;

namespace ZR.Common;

public static class IdUtils
{
    // public static string GetSerialNumber(string code)
    // {
    //     var vCode = new SugarParameter("@v_code", code);
    //     var vSerialNumber = new SugarParameter("@v_serialnumber", null, true);
    //     vSerialNumber.DbType = System.Data.DbType.String;
    //     //TODO 会抛异常
    //     DbScoped.SugarScope.GetConnectionScope(0).CopyNew().Ado.UseStoredProcedure()
    //         .GetDataTable("p_get_serialnumber", vCode, vSerialNumber);
    //         // .SqlQuerySingle<string>("p_get_serialnumber", vCode, vSerialNumber);
    //     Console.WriteLine(vSerialNumber.Value.ToString());
    //     return vSerialNumber.Value.ToString();
    // }

    public static string GetSerialNumber(string code)
    {
        var serialNumber = string.Empty;
        
        var tmpVal = string.Empty;
        var resStr = string.Empty;
        // var sp = string.Empty;
        // 当前值(加1)
        int? nextValue = 0;
        // 目标值(加cnt)
        int? destValue = 0;
        // 循环值
        int? cycleValue = 0;
        // 系统类型值
        var sysTypeValue = string.Empty;
        // 类型值
        var typeValue = string.Empty;
        
        using var db = DbScoped.SugarScope.GetConnectionScope("0");
        try
        {
            db.Ado.BeginTran();
            var codeRule = db.Queryable<CodeRule>()
                    .TranLock(DbLockType.Wait)
                    .First(it => it.Code == code);
            if (codeRule.CurrVal == 0)
            {
                nextValue = codeRule.IniVal;
            }
            else
            {
                nextValue = codeRule.CurrVal + codeRule.Step;
            }

            // cycleValue = codeRule.CycleVal;
            typeValue = codeRule.TypeVal;

            cycleValue = codeRule.CycleVal ?? 1;

            switch (codeRule.Type)
            {
                case "YYYY":
                    sysTypeValue = DateTime.Now.ToString("yyyy");
                    break;
                case "YYYYMM":
                    sysTypeValue = DateTime.Now.ToString("yyyyMM");
                    break;
                case "YYYYMMDD":
                    sysTypeValue = DateTime.Now.ToString("yyyyMMdd");
                    break;
                default:
                    sysTypeValue = " ";
                    break;
            }
            
            // 循环类型值改变，初始化类型循环
            if (string.IsNullOrWhiteSpace(sysTypeValue) != string.IsNullOrWhiteSpace(typeValue))
            {
                typeValue = sysTypeValue;
                cycleValue = 1;
                nextValue = codeRule.IniVal;
            }
            
            // 检查是否达到最大值，当达到最大值时抛出异常
            if (codeRule.FinishVal != null)
            {
                if (codeRule.Cycle != 1)
                {
                    // 不是循环，有循环不会引发最大值错误
                    if (codeRule.Step > 0)
                    {
                        if (nextValue > codeRule.FinishVal)
                        {
                            serialNumber = "-1";
                        }
                    }
                    else
                    {
                        if (nextValue < codeRule.FinishVal)
                        {
                            serialNumber = "-1";
                        }
                    }
                }
            }

            destValue = nextValue;
            
            // 计算取值，如果非循环，数量不足时把剩下的取出返回，如果循环，则循环取

            if (codeRule.FinishVal != null)
            {
                if (codeRule.Step > 0)
                {
                    if (destValue > codeRule.FinishVal)
                    {
                        if (codeRule.Cycle == 1)
                        {
                            cycleValue = cycleValue + 1;
                            destValue = codeRule.IniVal;
                        }
                        else
                        {
                            
                        }
                    }
                }
                else
                {
                    if (destValue < codeRule.FinishVal)
                    {
                        if (codeRule.Cycle == 1)
                        {
                            cycleValue = cycleValue + 1;
                            destValue = codeRule.IniVal;
                        }
                        else
                        {
                            
                        }
                    }
                }
            }
            
            // 生成值字符串，逗号分割
            tmpVal = $"{typeValue}{destValue.ToString().PadLeft(codeRule.Width, codeRule.FillChar[0])}";

            if (!string.IsNullOrWhiteSpace(codeRule.Prefix))
            {
                tmpVal = $"{codeRule.Prefix}{codeRule.JoinChar ?? string.Empty}{tmpVal}";
            }

            if (!string.IsNullOrWhiteSpace(codeRule.Sufix))
            {
                tmpVal = $"{tmpVal}{codeRule.JoinChar ?? string.Empty}{codeRule.Sufix}";
            }

            resStr = tmpVal;

            serialNumber = resStr;
            
            var foundRows = db.Updateable<CodeRule>()
                .SetColumns(it => new CodeRule
                {
                    TypeVal = typeValue,
                    CycleVal = cycleValue,
                    CurrVal = destValue,
                    Version = codeRule.Version + 1
                })
                .Where(it => it.Code == code && it.Version == codeRule.Version)
                .ExecuteCommand();
            if (foundRows != 0) db.Ado.CommitTran();
        }
        catch (Exception e)
        {
            // 没有对应更新行，说明被别人更新了，重新计算
            serialNumber = "-1";
            db.Ado.RollbackTran();
            throw;
        }
        return serialNumber;
    }
}
[SugarTable("base_coderule")]
[Tenant("0")]
public class CodeRule
{
    /// <summary>
    /// 代码
    /// </summary>
    [SugarColumn(IsPrimaryKey = true)]
    public string Code { get; set; }
    
    /// <summary>
    /// 名称
    /// </summary>
    public string Name { get; set; }
    
    /// <summary>
    /// 类型
    /// </summary>
    public string Type { get; set; }
    
    /// <summary>
    /// 前缀
    /// </summary>
    public string Prefix { get; set; }
    
    /// <summary>
    /// 宽度
    /// </summary>
    public int Width { get; set; }
    
    /// <summary>
    /// 初始值
    /// </summary>
    public int IniVal { get; set; }
    
    /// <summary>
    /// 增量
    /// </summary>
    public int Step { get; set; }
    
    /// <summary>
    /// 终止值
    /// </summary>
    public int? FinishVal { get; set; }
    
    /// <summary>
    /// 循环
    /// </summary>
    public int Cycle { get; set; }
    
    /// <summary>
    /// 后缀
    /// </summary>
    public string Sufix { get; set; }
    
    /// <summary>
    /// 分隔符
    /// </summary>
    public string JoinChar { get; set; }
    
    /// <summary>
    /// 填充符
    /// </summary>
    public string FillChar { get; set; }
    
    /// <summary>
    /// 类型值
    /// </summary>
    public string TypeVal { get; set; }
    
    /// <summary>
    /// 循环号
    /// </summary>
    public int? CycleVal { get; set; }
    
    /// <summary>
    /// 当前值
    /// </summary>
    public int? CurrVal { get; set; }
    
    /// <summary>
    /// 版本号
    /// </summary>
    public int Version { get; set; }
}